<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>关系图节点右键菜单</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/relation-graph@2.0.14/dist/relation-graph.min.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/relation-graph@2.0.14/dist/relation-graph.min.css">
  <style>
    body {
      margin: 0;
      padding: 0;
      font-family: Arial, sans-serif;
      background-color: #f5f7fa;
    }
    #app {
      height: 100vh;
      display: flex;
      flex-direction: column;
    }
    .header {
      padding: 15px 20px;
      background-color: #fff;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
      z-index: 10;
    }
    .header h1 {
      margin: 0;
      font-size: 20px;
      color: #333;
    }
    .graph-container {
      flex: 1;
      border: #efefef solid 1px;
      margin: 15px;
      background-color: #fff;
      border-radius: 4px;
      position: relative;
      overflow: hidden;
    }
    
    /* 自定义节点样式 */
    .custom-node {
      width: 150px;
      height: 200px;
      background-color: #3783c0;
      border-radius: 4px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
      color: white;
      overflow: hidden;
    }
    
    .node-header {
      padding: 10px;
      background-color: #2a6aa5;
      text-align: center;
      font-weight: bold;
    }
    
    .c-data-table {
      background-color: #ffffff;
      border-collapse: collapse;
      width: 100%;
    }
    
    .c-data-table td, .c-data-table th {
      border: 1px solid #3783c0;
      color: #333333;
      padding: 5px;
      padding-left: 20px;
      padding-right: 20px;
    }
    
    .c-data-table td div, .c-data-table th div {
      background-color: #1da9f5;
      color: #ffffff;
      border-radius: 5px;
      padding: 2px 5px;
      text-align: center;
    }
    
    /* 右键菜单样式 */
    .context-menu {
      width: 150px;
      background: white;
      border-radius: 4px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
      border: 1px solid #e0e0e0;
      padding: 5px 0;
      position: fixed;
      z-index: 1000;
    }
    
    .menu-item {
      padding: 8px 15px;
      font-size: 14px;
      cursor: pointer;
      transition: background 0.2s;
    }
    
    .menu-item:hover {
      background-color: #f5f5f5;
      color: #1890ff;
    }
    
    .menu-divider {
      height: 1px;
      background-color: #e0e0e0;
      margin: 5px 0;
    }
    
    /* 模态框样式 */
    .modal-overlay {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.5);
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 2000;
    }
    
    .modal-content {
      background: white;
      border-radius: 8px;
      padding: 20px;
      width: 400px;
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    }
    
    .modal-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 20px;
    }
    
    .modal-title {
      font-size: 18px;
      font-weight: bold;
      color: #333;
    }
    
    .close-button {
      background: none;
      border: none;
      font-size: 20px;
      cursor: pointer;
      color: #999;
    }
    
    .form-group {
      margin-bottom: 15px;
    }
    
    .form-group label {
      display: block;
      margin-bottom: 5px;
      font-weight: bold;
      color: #555;
    }
    
    .form-group input {
      width: 100%;
      padding: 8px 12px;
      border: 1px solid #ddd;
      border-radius: 4px;
      font-size: 14px;
    }
    
    .form-actions {
      display: flex;
      justify-content: flex-end;
      gap: 10px;
      margin-top: 20px;
    }
    
    .btn {
      padding: 8px 16px;
      border-radius: 4px;
      font-size: 14px;
      cursor: pointer;
      border: none;
    }
    
    .btn-primary {
      background-color: #1890ff;
      color: white;
    }
    
    .btn-default {
      background-color: #f5f5f5;
      color: #333;
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="header">
      <h1>关系图节点右键菜单示例</h1>
    </div>
    
    <div class="graph-container">
      <relation-graph ref="graphRef" :options="graphOptions" @contextmenu="handleRightClick">
        <template #node="{ node }">
          <div class="custom-node">
            <div class="node-header">{{ node.text }}</div>
            <table class="c-data-table">
              <tr>
                <th>名称</th>
                <th>类型</th>
              </tr>
              <template v-for="column of node.data.columns" :key="column.columnName">
                <tr>
                  <td>
                    <div :id="`${node.id}-${column.columnName}`">{{ column.columnName }}</div>
                  </td>
                  <td>{{ column.dataType }}</td>
                </tr>
              </template>
            </table>
          </div>
        </template>
      </relation-graph>
    </div>

    <!-- 节点右键菜单 -->
    <div v-if="showNodeContextMenu" :style="nodeContextMenuStyle" class="context-menu" @click.stop>
      <div class="menu-item" @click="designTable">设计表</div>
      <div class="menu-item" @click="renameTable">重命名</div>
      <div class="menu-divider"></div>
      <div class="menu-item" @click="deleteTable">删除表</div>
    </div>

    <!-- 画布右键菜单 -->
    <div v-if="showCanvasContextMenu" :style="canvasContextMenuStyle" class="context-menu" @click.stop>
      <div class="menu-item" @click="addNode">添加节点</div>
      <div class="menu-item" @click="clearGraph">清空图表</div>
      <div class="menu-item" @click="downloadGraph">下载图表</div>
    </div>

    <!-- 设计表模态框 -->
    <div v-if="showDesignModal" class="modal-overlay" @click.self="showDesignModal = false">
      <div class="modal-content">
        <div class="modal-header">
          <div class="modal-title">设计表: {{ currentNode.text }}</div>
          <button class="close-button" @click="showDesignModal = false">×</button>
        </div>
        <div class="form-group">
          <label>表名</label>
          <input type="text" v-model="currentNode.text">
        </div>
        <div class="form-group">
          <label>字段列表</label>
          <div v-for="(column, index) in currentNode.data.columns" :key="index" style="display: flex; margin-bottom: 8px;">
            <input type="text" v-model="column.columnName" placeholder="字段名" style="flex: 1; margin-right: 8px;">
            <input type="text" v-model="column.dataType" placeholder="类型" style="width: 100px;">
          </div>
        </div>
        <div class="form-actions">
          <button class="btn btn-default" @click="showDesignModal = false">取消</button>
          <button class="btn btn-primary" @click="saveTableDesign">保存</button>
        </div>
      </div>
    </div>

    <!-- 重命名模态框 -->
    <div v-if="showRenameModal" class="modal-overlay" @click.self="showRenameModal = false">
      <div class="modal-content">
        <div class="modal-header">
          <div class="modal-title">重命名表</div>
          <button class="close-button" @click="showRenameModal = false">×</button>
        </div>
        <div class="form-group">
          <label>新表名</label>
          <input type="text" v-model="newTableName" placeholder="输入新表名">
        </div>
        <div class="form-actions">
          <button class="btn btn-default" @click="showRenameModal = false">取消</button>
          <button class="btn btn-primary" @click="saveRename">保存</button>
        </div>
      </div>
    </div>
  </div>

  <script>
    const { createApp, ref, onMounted } = Vue;
    
    const app = createApp({
      setup() {
        const graphRef = ref(null);
        const showNodeContextMenu = ref(false);
        const showCanvasContextMenu = ref(false);
        const nodeContextMenuStyle = ref({ left: '0px', top: '0px' });
        const canvasContextMenuStyle = ref({ left: '0px', top: '0px' });
        const currentNode = ref(null);
        const showDesignModal = ref(false);
        const showRenameModal = ref(false);
        const newTableName = ref('');
        
        // 示例数据
        const graphData = {
          rootId: 'root',
          nodes: [
            {
              id: '1',
              text: '用户表',
              x: 100,
              y: 100,
              data: {
                columns: [
                  { columnName: 'id', dataType: 'int' },
                  { columnName: 'name', dataType: 'varchar(50)' },
                  { columnName: 'email', dataType: 'varchar(100)' }
                ]
              }
            },
            {
              id: '2',
              text: '订单表',
              x: 400,
              y: 100,
              data: {
                columns: [
                  { columnName: 'id', dataType: 'int' },
                  { columnName: 'user_id', dataType: 'int' },
                  { columnName: 'amount', dataType: 'decimal' }
                ]
              }
            },
            {
              id: '3',
              text: '产品表',
              x: 250,
              y: 300,
              data: {
                columns: [
                  { columnName: 'id', dataType: 'int' },
                  { columnName: 'name', dataType: 'varchar(100)' },
                  { columnName: 'price', dataType: 'decimal' }
                ]
              }
            }
          ],
          lines: [
            { from: '1', to: '2', text: '拥有' },
            { from: '2', to: '3', text: '包含' }
          ]
        };
        
        const graphOptions = {
          defaultExpandHolderPosition: 'right',
          allowNodeDrag: true,
          allowShowDownloadButton: false,
          layout: {
            layoutName: 'fixed'
          }
        };
        
        onMounted(() => {
          if (graphRef.value) {
            graphRef.value.setJsonData(graphData, () => {
              console.log('图表加载完成');
            });
          }
        });
        
        const handleRightClick = (event, node) => {
          event.preventDefault();
          event.stopPropagation();
          
          // 关闭所有菜单
          showNodeContextMenu.value = false;
          showCanvasContextMenu.value = false;
          
          if (node) {
            // 右键点击的是节点
            currentNode.value = node;
            showNodeContextMenu.value = true;
            nodeContextMenuStyle.value = {
              left: `${event.clientX}px`,
              top: `${event.clientY}px`
            };
          } else {
            // 右键点击的是画布
            showCanvasContextMenu.value = true;
            canvasContextMenuStyle.value = {
              left: `${event.clientX}px`,
              top: `${event.clientY}px`
            };
          }
          
          // 点击其他地方关闭菜单
          const closeMenu = () => {
            showNodeContextMenu.value = false;
            showCanvasContextMenu.value = false;
            document.removeEventListener('click', closeMenu);
          };
          
          setTimeout(() => {
            document.addEventListener('click', closeMenu);
          }, 0);
        };
        
        const designTable = () => {
          showDesignModal.value = true;
          showNodeContextMenu.value = false;
        };
        
        const renameTable = () => {
          newTableName.value = currentNode.value.text;
          showRenameModal.value = true;
          showNodeContextMenu.value = false;
        };
        
        const deleteTable = () => {
          if (confirm(`确定要删除表 "${currentNode.value.text}" 吗？`)) {
            const index = graphData.nodes.findIndex(n => n.id === currentNode.value.id);
            if (index !== -1) {
              graphData.nodes.splice(index, 1);
              graphRef.value.setJsonData(graphData);
            }
          }
          showNodeContextMenu.value = false;
        };
        
        const addNode = () => {
          const newNodeId = `node_${Date.now()}`;
          graphData.nodes.push({
            id: newNodeId,
            text: '新表',
            x: parseInt(canvasContextMenuStyle.value.left) + 20,
            y: parseInt(canvasContextMenuStyle.value.top) + 20,
            data: {
              columns: [
                { columnName: 'id', dataType: 'int' },
                { columnName: 'created_at', dataType: 'datetime' }
              ]
            }
          });
          graphRef.value.setJsonData(graphData);
          showCanvasContextMenu.value = false;
        };
        
        const clearGraph = () => {
          if (confirm('确定要清空图表吗？')) {
            graphData.nodes = [];
            graphData.lines = [];
            graphRef.value.setJsonData(graphData);
          }
          showCanvasContextMenu.value = false;
        };
        
        const downloadGraph = () => {
          graphRef.value.downloadGraph();
          showCanvasContextMenu.value = false;
        };
        
        const saveTableDesign = () => {
          // 在实际应用中，这里可以保存表设计到后端
          showDesignModal.value = false;
          graphRef.value.setJsonData(graphData);
        };
        
        const saveRename = () => {
          currentNode.value.text = newTableName.value;
          showRenameModal.value = false;
          graphRef.value.setJsonData(graphData);
        };
        
        return {
          graphRef,
          graphOptions,
          showNodeContextMenu,
          showCanvasContextMenu,
          nodeContextMenuStyle,
          canvasContextMenuStyle,
          showDesignModal,
          showRenameModal,
          newTableName,
          currentNode,
          handleRightClick,
          designTable,
          renameTable,
          deleteTable,
          addNode,
          clearGraph,
          downloadGraph,
          saveTableDesign,
          saveRename
        };
      }
    });
    
    app.use(RelationGraph);
    app.mount('#app');
  </script>
</body>
</html>